﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Collections;

namespace PolePosition.v3.Desktop.Selectors.Controls
{
    public partial class ListSelector : UserControl
    {
        public EventHandler<ItemCheckedEventArgs> ItemChecked;

        public ListSelector()
        {
            InitializeComponent();
        }

        private bool m_SuspendItemCheckEvent;

        [DefaultValue("Column Header")]
        public string ColumnHeaderText 
        {
            get
            {
                return listColumn1.Text;
            }
            set
            {
                listColumn1.Text = value;
            }
        }

        private string m_DisplayMember = null;
        public string DisplayMember
        {
            get { return m_DisplayMember; }
            set 
            { 
                m_DisplayMember = value;
                Bind();
            } 
        }

        private string m_ValueMember = null;
        public string ValueMember
        {
            get { return m_ValueMember; }
            set
            {
                m_ValueMember = value;
                if (m_DataSource != null)
                    Bind();
            }
        }

        private object m_DataSource = null;
        public object DataSource
        {
            get { return m_DataSource; }
            set
            {
                m_DataSource = value;
                Bind();
            }
        }

        public new bool Enabled 
        {
            get
            {
                return base.Enabled;
            }
            set
            {
                if (value)
                    listViewEx1.BackColor = System.Drawing.Color.White;
                else
                    listViewEx1.BackColor  = System.Drawing.SystemColors.InactiveBorder;

                base.Enabled = value;
            }
        }

        private bool m_AllowMultiSelect = true;
        [DefaultValue(true)]
        public bool AllowMultiSelect
        {
            get
            {
                return m_AllowMultiSelect;
            }
            set
            {
                m_AllowMultiSelect = value;
                listViewEx1.CheckBoxes = value;
                barList.Visible = value;
                listViewEx1.MultiSelect = m_AllowMultiSelect;
            }
        }

        [DefaultValue(true)]
        public bool NavigationVisible
        {
            get
            {
                return barList.Visible;
            }
            set
            {
                if (value && m_AllowMultiSelect)
                    barList.Visible = true;
                else
                    barList.Visible = false;
            }
        }

        [DefaultValue(true)]
        public bool ListHeaderVisible
        {
            get
            {
                if (listViewEx1.HeaderStyle == ColumnHeaderStyle.None)
                    return false;
                else
                    return true;
            }
            set
            {
                if (value)
                    listViewEx1.HeaderStyle = ColumnHeaderStyle.Clickable;
                else
                    listViewEx1.HeaderStyle = ColumnHeaderStyle.None;
            }
        }

        [DefaultValue(false)]
        public bool ReadOnly { get; set; }

        [DefaultValue(false)]
        public bool ReadOnlyNoneSelectedVisible 
        {
            get { return labelReadOnlyNoneSelected.Visible; } 
            set { labelReadOnlyNoneSelected.Visible = value; } 
        }

        [DefaultValue(false)]
        public bool LoadingVisible 
        {
            get { return pictureBoxLoading.Visible; }
            set 
            {
                if (value)
                { 
                    //center the picturebox
                    int _Halfway = listViewEx1.Width / 2;
                    int _Left = _Halfway - (pictureBoxLoading.Width/2);
                    if (_Left < 0)
                        _Left = 0;


                    pictureBoxLoading.Location = new Point(_Left, listViewEx1.Top + 5);
                }

                pictureBoxLoading.Visible = value; 
            } 
        }

        public bool AllItemsChecked 
        {
            get
            {
                if (m_AllowMultiSelect)
                    return (listViewEx1.CheckedItems.Count == listViewEx1.Items.Count);
                else
                    return false;
            }
        }

        public ListView.ListViewItemCollection ListItems 
        {
            get { return this.listViewEx1.Items; }
        }

        private void ListSelector_Load(object sender, EventArgs e)
        {

        }

        private void Bind()
        {
            if (string.IsNullOrEmpty(m_DisplayMember))
                return;

            if (m_DataSource == null)
                return;

            m_SuspendItemCheckEvent = true;

            this.listViewEx1.Items.Clear();

            foreach (object _Entity in m_DataSource as IList)
            {
                string _Text = GetProperty<string>(_Entity, m_DisplayMember);

                ListViewItem _ListViewItem;
                _ListViewItem = new ListViewItem();
                _ListViewItem.Tag = _Entity;
                _ListViewItem.Text = _Text;
                if (m_AllowMultiSelect)
                    _ListViewItem.Checked = true;
                this.listViewEx1.Items.Add(_ListViewItem);

                ListViewItem.ListViewSubItem _ListViewSubItem;
                _ListViewSubItem = new ListViewItem.ListViewSubItem();
                _ListViewSubItem.Text = _Text;
                _ListViewItem.SubItems.Insert(0, _ListViewSubItem);
            }
            ResizeColumnForListItems();

            m_SuspendItemCheckEvent = false;
        }

        public void SelectAll()
        {
            if (!m_AllowMultiSelect)
                return;

            m_SuspendItemCheckEvent = true;

            foreach (ListViewItem _Item in listViewEx1.Items)
            {
                if (!_Item.Checked)
                    _Item.Checked = true;
            }

            m_SuspendItemCheckEvent = false;
        }

        public void SelectNone()
        {
            if (!m_AllowMultiSelect)
                return;

            m_SuspendItemCheckEvent = true;

            foreach (ListViewItem _Item in listViewEx1.Items)
            {
                if (_Item.Checked)
                    _Item.Checked = false;
            }

            m_SuspendItemCheckEvent = false;
        }

        public void AddBlankOption<itemType>()
        {
            if (string.IsNullOrEmpty(DisplayMember))
                return;

            if (string.IsNullOrEmpty(ValueMember))
                return;

            //create a new item type
            itemType _Tag = (itemType) typeof(itemType).GetConstructor(new System.Type[] { }).Invoke(null);

            System.Reflection.PropertyInfo _PropertyInfo;
            _PropertyInfo = _Tag.GetType().GetProperty(ValueMember);
            _PropertyInfo.SetValue(_Tag, -1, null);

            _PropertyInfo = _Tag.GetType().GetProperty(DisplayMember);
            _PropertyInfo.SetValue(_Tag, "[Blank]", null);

            listViewEx1.Items.Insert(0, new ListViewItem()
            {
                Tag = _Tag,
                Text = "[Blank]",
                Checked = true
            });

        }

        public List<itemType> GetSelectedItems<itemType>()
        {
            List<itemType> _SelectedItems = new List<itemType>();
            if (!m_AllowMultiSelect)
            {
                if (listViewEx1.SelectedItems != null && listViewEx1.SelectedItems.Count != 0)
                    _SelectedItems.Add((itemType)listViewEx1.SelectedItems[0].Tag);
            }
            else
            {
                foreach (ListViewItem _Item in listViewEx1.Items)
                {
                    if (_Item != null && _Item.Checked)
                        _SelectedItems.Add((itemType)_Item.Tag);
                }
            }

            return _SelectedItems;
        }

        public List<valueType> GetSelectedValues<valueType>()
        {
            List<valueType> _SelectedValues = new List<valueType>();
            if (!m_AllowMultiSelect)
            {
                if (listViewEx1.SelectedItems != null && listViewEx1.SelectedItems.Count != 0)
                {
                    if (string.IsNullOrEmpty(ValueMember))
                    {
                        TypeConverter _TypeConverter;
                        _TypeConverter = TypeDescriptor.GetConverter(typeof(valueType));

                        if (_TypeConverter.CanConvertFrom(typeof(string)))
                            _SelectedValues.Add((valueType)_TypeConverter.ConvertFrom(listViewEx1.SelectedItems[0].Text));
                    }
                    else
                    {
                        valueType _Value = GetProperty<valueType>(listViewEx1.SelectedItems[0].Tag, ValueMember);
                        _SelectedValues.Add((valueType)_Value);
                    }
                }
            }
            else
            {
                foreach (ListViewItem _Item in listViewEx1.Items)
                {
                    if (_Item.Checked)
                    {
                        if (string.IsNullOrEmpty(ValueMember))
                        {
                            TypeConverter _TypeConverter;
                            _TypeConverter = TypeDescriptor.GetConverter(typeof(valueType));

                            if (_TypeConverter.CanConvertFrom(typeof(string)))
                            {
                                if (_Item.Text.Equals("[Blank]")) 
                                    _SelectedValues.Add((valueType)_TypeConverter.ConvertFrom("-1"));
                                else
                                    _SelectedValues.Add((valueType)_TypeConverter.ConvertFrom(_Item.Text));
                            }
                            
                        }
                        else
                        {
                            valueType _Value = GetProperty<valueType>(_Item.Tag, ValueMember);
                            _SelectedValues.Add((valueType)_Value);
                        }
                    }
                }
            }

            return _SelectedValues;
        }

        public string GetSelectedValueList<valueType>()
        {
            List<valueType> _SelectedList;
            _SelectedList = GetSelectedValues<valueType>();

            return string.Join(",", _SelectedList.Select(x => x.ToString()).ToArray());
        }

        public void SetSelectedItems<itemType>(List<itemType> items)
        {
            if (listViewEx1.Items == null || listViewEx1.Items.Count == 0)
                return;

            if (items.Count() == listViewEx1.Items.Count)
                return;

            //clear all selected
            foreach (ListViewItem _Item in listViewEx1.Items)
            {
                _Item.Selected = false;
                
                if (m_AllowMultiSelect)
                    _Item.Checked = false;
            }

            if (items != null)
            {
                foreach (ListViewItem _Item in listViewEx1.Items)
                {
                    itemType _TagValue;
                    _TagValue = (itemType)_Item.Tag;

                    var _find = (from finditem in items
                                 where finditem.Equals(_TagValue)
                                 select finditem).FirstOrDefault();

                    if (_find != null)
                    {
                        _Item.Selected = true;
                        //only select one otherwise check
                        if (m_AllowMultiSelect)
                            _Item.Checked = true;
                        else
                            break;
                    }
                }
            }
        }

        public void SetSelectedValues<valueType>(List<valueType> values)
        {
            if (listViewEx1.Items == null || listViewEx1.Items.Count == 0)
                return;

            //clear all selected
            foreach (ListViewItem _Item in listViewEx1.Items)
            {
                _Item.Selected = false;

                if (m_AllowMultiSelect)
                    _Item.Checked = false;
            }

            if (values != null)
            {
                foreach (ListViewItem _Item in listViewEx1.Items)
                {
                    valueType _Value = default(valueType);

                    if (string.IsNullOrEmpty(ValueMember))
                    {
                        TypeConverter _TypeConverter;
                        _TypeConverter = TypeDescriptor.GetConverter(typeof(valueType));

                        if (_TypeConverter.CanConvertFrom(typeof(string)))
                        {
                            if (_Item.Text.Equals("[Blank]"))
                                _Value = (valueType) _TypeConverter.ConvertFrom("-1");
                            else
                                _Value = (valueType)_TypeConverter.ConvertFrom(_Item.Text);
                        }

                    }
                    else
                    {
                        _Value = GetProperty<valueType>(_Item.Tag, ValueMember);

                    }

                    var _find = (from findValue in values
                                 where findValue.Equals(_Value)
                                 select findValue);

                    if (_find.Count() > 0)
                    {
                        _Item.Selected = true;
                        //only select one otherwise check
                        if (m_AllowMultiSelect)
                            _Item.Checked = true;
                        else
                            break;
                    }
                    
                }
            }

            //m_SuspendItemCheckEvent = false;
        }

        public void SetSelectedValueList<valueType>(string values)
        {
            if (string.IsNullOrEmpty(values))
                return;

            string[] _Values;
            _Values = values.Split(new char[] { ',' });

            if (_Values.Count() == listViewEx1.Items.Count)
                return;

            TypeConverter _TypeConverter;
            _TypeConverter = TypeDescriptor.GetConverter(typeof(valueType));

            List<valueType> _SelectedList;
            _SelectedList = new List<valueType>();

            foreach (string _Value in _Values)
            {
                if (_TypeConverter.CanConvertFrom(typeof(string)))
                    _SelectedList.Add((valueType) _TypeConverter.ConvertFrom(_Value));
            }

            SetSelectedValues<valueType>(_SelectedList);
        }

        public void ResizeColumnForListItems()
        {
            if (listViewEx1.Items.Count * 21.25 > this.Height)
                listColumn1.Width = this.Width - 20;
            else
                listColumn1.Width = this.Width;
        }

        private T GetProperty<T>(object _Entity, string propertyName)
        {
            if (_Entity == null)
                ProjectCommon2.Helpers.ExceptionHelper.Throw(new ArgumentNullException("Entity"));

            System.Reflection.PropertyInfo _PropertyInfo;
            _PropertyInfo = _Entity.GetType().GetProperty(propertyName);

            if (_PropertyInfo == null)
                ProjectCommon2.Helpers.ExceptionHelper.Throw(new Exception(propertyName + " property not found in entity."));

            object _Object;
            _Object = _PropertyInfo.GetValue(_Entity, null);
            return (T)_Object;
        }

        private void buttonItemCheckAll_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem _Item in listViewEx1.Items)
            {
                _Item.Checked = true;
            }
        }

        private void buttonItemUncheckAll_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem _Item in listViewEx1.Items)
            {
                _Item.Checked = false;
            }
        }

        private void buttonItemSearch_Click(object sender, EventArgs e)
        {
            //
        }

        private void listViewEx1_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            if (m_SuspendItemCheckEvent)
                return;

            if (ReadOnly && e.NewValue != e.CurrentValue)
            {
                e.NewValue = e.CurrentValue;
                return;
            }

            if (ItemChecked != null)
                ItemChecked(this, new ItemCheckedEventArgs(listViewEx1.Items[e.Index])); 
        }

        internal void Clear()
        {
            listViewEx1.Items.Clear();
        }
    }

    public class ItemCheckedEventArgs : EventArgs
    {
        private ListViewItem _item;

        public ListViewItem ItemChecked
        {
            get
            {
                return _item;
            }
        }

        public ItemCheckedEventArgs(ListViewItem item)
        {
            _item = item;
        }
    }
}